package ai;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 单例模式构造分值计算类.
 *
 * @author 任禹名
 */
public class Values {
    private static Values instance;

    private Values() {
    }

    public static Values getInstance() {
        if (instance == null)
            instance = new Values();
        return instance;
    }

    /**
     * 获取当前位置分值.
     *
     * @param x
     * @param y
     * @param player
     * @param table
     * @return 当前位置分值
     */
    public int getValue(int x, int y, int player, ChessNode[][] table) {
        Level level1 = getLevel(x, y, Direction.HENG, player, table);
        Level level2 = getLevel(x, y, Direction.SHU, player, table);
        Level level3 = getLevel(x, y, Direction.PIE, player, table);
        Level level4 = getLevel(x, y, Direction.NA, player, table);
        return levelScore(level1, level2, level3, level4) + position[x][y];
    }

    //

    /**
     * 获取四个方向总分值.
     *
     * @param level1 横向棋形
     * @param level2 竖向棋形
     * @param level3 撇向棋形
     * @param level4 捺向棋形
     * @return 四个方向总分值
     */
    private int levelScore(Level level1, Level level2, Level level3, Level level4) {
        int[] levelCount = new int[Level.values().length];
        for (int i = 0; i < Level.values().length; i++) {
            levelCount[i] = 0;
        }


        // 统计棋形数量
        levelCount[level1.index]++;
        levelCount[level2.index]++;
        levelCount[level3.index]++;
        levelCount[level4.index]++;

        int score = 0;
        if (levelCount[Level.GO_4.index] >= 2
                || levelCount[Level.GO_4.index] >= 1 && levelCount[Level.ALIVE_3.index] >= 1) {// 冲四活三

            score = 10000;
        } else if (levelCount[Level.ALIVE_3.index] >= 2) {// 双活三
            score = 5000;
        } else if (levelCount[Level.SLEEP_3.index] >= 1 && levelCount[Level.ALIVE_3.index] >= 1) {// 眠三活三
            score = 1000;
        } else if (levelCount[Level.ALIVE_2.index] >= 2) {// 双活二
            score = 100;
        } else if (levelCount[Level.SLEEP_2.index] >= 1 && levelCount[Level.ALIVE_2.index] >= 1) {// 眠二活二
            score = 10;
        }
        score = Math.max(score, Math.max(Math.max(level1.score, level2.score), Math.max(level3.score, level4.score)));
        return score;
    }

    /**
     * 获取当前方向匹配的棋形.
     *
     * @param x
     * @param y
     * @param direction 方向
     * @param player
     * @param table
     * @return 当前方向匹配的棋形
     */
    private Level getLevel(int x, int y, Direction direction, int player, ChessNode[][] table) {
        String leftString = "";
        String rightString = "";
        String str;

        //横竖撇捺
        if (direction == Direction.HENG) {
            leftString = getStringSeq(x, y, -1, 0, player, table);
            rightString = getStringSeq(x, y, 1, 0, player, table);
        } else if (direction == Direction.SHU) {
            leftString = getStringSeq(x, y, 0, -1, player, table);
            rightString = getStringSeq(x, y, 0, 1, player, table);
        } else if (direction == Direction.PIE) {
            leftString = getStringSeq(x, y, -1, 1, player, table);
            rightString = getStringSeq(x, y, 1, -1, player, table);
        } else if (direction == Direction.NA) {
            leftString = getStringSeq(x, y, -1, -1, player, table);
            rightString = getStringSeq(x, y, 1, 1, player, table);
        }

        str = leftString + player + rightString;
        //利用正则表达式将字符串正反各匹配一次
        table[x][y].getBuffer().append("(" + (x + 1) + "," + (y - 1) + ")" + direction + "\t" + str + "\t");//无意义,调试的时候可以按方向输出字符串
        String rstr = new StringBuilder(str).reverse().toString();//反
        for (Level level : Level.values()) {
            Pattern pattern = Pattern.compile(level.regex[player - 1]);
            Matcher matcher = pattern.matcher(str); // 正
            boolean result1 = matcher.find();
            matcher = pattern.matcher(rstr); // 反
            boolean result2 = matcher.find();
            if (result1 || result2) {
                table[x][y].getBuffer().append(level.name + "\n");
                if (direction == Direction.NA) {
                    table[x][y].getBuffer().append("\n");
                }
                return level;
            }
        }
        return Level.NULL;
    }

    /**
     * 将棋盘上某棋子某方向上5个棋子转化为字符串.
     *
     * @param x
     * @param y
     * @param i      横向移动方向与步数,-1代表向上移动一格
     * @param j      竖向移动方向与步数,-1代表向左移动一格
     * @param player
     * @param table
     * @return 棋子转化的字符串
     */
    private String getStringSeq(int x, int y, int i, int j, int player, ChessNode[][] table) {
        String sum = "";
        boolean isRight = false;
        int playerHere;
        if (i < 0 || (i == 0 && j < 0)) {
            isRight = true;
        }
        for (int k = 0; k < 5; k++) {
            x += i;
            y += j;
            if (x > 0 && x < 15 && y > 0 && y < 15) {
                if (table[x][y] == null) {
                    playerHere = 0;
                } else {
                    playerHere = table[x][y].getPlayer();
                }
                if (isRight) {
                    sum = playerHere + sum;
                } else {
                    sum = sum + playerHere;
                }
            }
        }
        return sum;
    }

    /**
     * 棋形枚举类，判断权重.
     */
    public enum Level {
        CON_5("长连", 0, new String[]{"11111", "22222"}, 100000),
        ALIVE_4("活四", 1, new String[]{"011110", "022220"}, 10000),
        GO_4("冲四", 2, new String[]{"011112|0101110|0110110", "022221|0202220|0220220"}, 500),
        DEAD_4("死四", 3, new String[]{"211112", "122221"}, -5),
        ALIVE_3("活四", 4, new String[]{"01110|010110", "02220|020220"}, 200),
        SLEEP_3("眠三", 5,
                new String[]{"001112|010112|011012|10011|10101|2011102", "002221|020221|022021|20022|20202|1022201"},
                50),
        DEAD_3("死三", 6, new String[]{"21112", "12221"}, -5),
        ALIVE_2("活二", 7, new String[]{"00110|01010|010010", "00220|02020|020020"}, 5),
        SLEEP_2("眠二", 8,
                new String[]{"000112|001012|010012|10001|2010102|2011002",
                        "000221|002021|020021|20002|1020201|1022001"},
                3),
        DEAD_2("死二", 9, new String[]{"2112", "1221"}, -5), NULL("null", 10, new String[]{"", ""}, 0);
        private String name;//棋形名
        private int index;//编号
        private String[] regex;// 正则表达式
        int score;//该棋形得分


        private Level(String name, int index, String[] regex, int score) {
            this.name = name;
            this.index = index;
            this.regex = regex;
            this.score = score;
        }


        @Override
        public String toString() {
            return this.name;
        }
    }


    /**
     * 横竖撇捺.
     */

    private enum Direction {
        HENG, SHU, PIE, NA
    }


    // 位置分
    private int[][] position = {
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
            {0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0},
            {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0},
            {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0},
            {0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0},
            {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
    };
}
